package fun.qu_an.velocity.whitelist.util;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.velocitypowered.api.util.UuidUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

import static fun.qu_an.velocity.whitelist.config.VelocityWhitelistConfig.CONFIG;

@SuppressWarnings("unused")
public class UuidApiUtils {
	/**
	 * 根据玩家名获取UUID
	 *
	 * @param playerName 玩家名，不区分大小写
	 * @param online     是否是在线模式
	 */
	public static @NotNull UUID getUuid(@NotNull String playerName, boolean online) throws IOException {
		if (online) {
			return UuidUtils.fromUndashed(getOnlinePlayerUuidJson(playerName)
				.get("uuid")
				.getAsString());
		}
		return UuidUtils.generateOfflinePlayerUuid(playerName);
	}

	/**
	 * 获取玩家UUID Json
	 *
	 * @return 在线模式返回获取到的玩家UUID Json，离线模式返回本地生成的
	 */
	public static @NotNull JsonObject getUuidJson(@NotNull String playerName, boolean online) throws IOException {
		if (online) {
			return getOnlinePlayerUuidJson(playerName);
		}
		return getOfflinePlayerUuidJson(playerName);
	}

	/**
	 * @return 在线模式返回获取到的玩家档案 Json，离线模式返回 null
	 */
	public static JsonObject getProfileJson(@NotNull UUID uuid, boolean online) throws IOException {
		if (online) return getOnlinePlayerProfileJson(uuid);
		return null;
	}

	private static @NotNull JsonObject getOfflinePlayerUuidJson(String playerName) {
		String uuid = UuidUtils.toUndashed(UuidUtils.generateOfflinePlayerUuid(playerName));
		JsonObject jsonObject = new JsonObject();
		jsonObject.addProperty("uuid", uuid);
		jsonObject.addProperty("name", playerName);
		return jsonObject;
	}

	private static @NotNull JsonObject getOnlinePlayerUuidJson(@NotNull String playerName) throws IOException {
		JsonObject jsonObject = getJsonFromUrl(getUuidApiUrl(playerName));
		String name = jsonObject.get("name").getAsString();
		if (!playerName.equalsIgnoreCase(name)) {
			throw new IOException("wrong player name is returned during calling the api!");
		}
		return jsonObject;
	}

	private static @NotNull JsonObject getOnlinePlayerProfileJson(@NotNull UUID uuid) throws IOException {
		JsonObject jsonObject = getJsonFromUrl(getProfileApiUrl(uuid));
		String uuidStr = jsonObject.get("uuid").getAsString();
		if (!UuidUtils.fromUndashed(uuidStr).equals(uuid)) {
			throw new IOException("wrong json format is returned during calling the api!");
		}
		return jsonObject;
	}

	@Contract("_ -> new")
	private static @NotNull URL getProfileApiUrl(@NotNull UUID uuid) throws MalformedURLException {
		return new URL(CONFIG.getProfileApi() + UuidUtils.toUndashed(uuid));
	}

	@Contract("_ -> new")
	private static @NotNull URL getUuidApiUrl(String playerName) throws MalformedURLException {
		return new URL(CONFIG.getUuidApi() + playerName);
	}

	private static @NotNull JsonObject getJsonFromUrl(@NotNull URL url) throws IOException {
		JsonObject jsonObject;
		try (InputStream is = url.openStream();
			 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)) {
			JsonElement jsonElement = JsonParser.parseReader(isr);
			if (!jsonElement.isJsonObject()) {
				throw new IOException("player not found or api connect failed!");
			}
			jsonObject = jsonElement.getAsJsonObject();
		}
		JsonElement jsonName = jsonObject.get("name");
		JsonElement jsonId = jsonObject.get("id");
		if (jsonName == null || jsonId == null) {
			throw new IOException("player not found or call api failed!");
		}
		if (!jsonName.isJsonPrimitive() || !jsonId.isJsonPrimitive()) {
			throw new IOException("wrong json format is returned during calling the api!");
		}
		String uuid = jsonId.getAsString();
		// 将“id”换为“uuid”
		jsonObject.addProperty("uuid", uuid);
		jsonObject.remove("id");
		return jsonObject;
	}
}
